using System;
using System.Diagnostics;
using System.IO;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Xfinity.AI;
using Xfinity.AI.Entities.Managers;
using Xfinity.Console;
using Xfinity.Engine;
using Xfinity.Engine.Plugins;
using Xfinity.Physics;
using Xfinity.Player;
using Xfinity.Scripting;
using Xfinity.Weapons;
using Xfinity.Debug;
using Xfinity.Rendering;
using System.Collections.Generic;
using Xfinity.Levels;
using Xfinity.Engine.GameStates;
using Xfinity.HUD;

namespace Xfinity
{
    /// <summary>
    /// The main Xfinity class
    /// </summary>
    public class GameManager : GlobalManager
    {
        
        /// <summary>
        /// Constructs a new GameManager.
        /// </summary>
        /// <param name="game">The Game being used.</param>
        public GameManager(Game game)
            : base("Game Manager", false, game)
        {

            if (game == null)
            {
                throw new ArgumentNullException("game");
            }
            Trace.Listeners.Add(new Xfinity.Console.Console.ConsoleTraceListener());
            GameManager.game = game;
            playerManager = new PlayerManager("", game);
            aiManager = new AIManager(playerManager.PlayerName + Resources.AIManager, game);
            content = new ContentManager(game.Services);
            camera = new Camera(game);
            game.Components.Add(camera);
            weaponManager = new WeaponManager(playerManager.PlayerName + " Weapon Manager", game);
            new PhysicsManager(game);
            scriptManager = new ScriptManager("Script manager", game);
            CommandParser.ScanForBoundCommands();
            currentState = new MenuGameState();
            new InputHandler(game);
            StandardConsole.DefaultConsole = new Xfinity.Console.Console();
            HeadsUpDisplayComponent hud = new HeadsUpDisplayComponent();
            hud.Visible = true;
            hud.DrawOrder = int.MaxValue;
            game.Components.Add(hud);
            BloomComponent bloom = new BloomComponent(game);
            game.Components.Add(bloom);
        }

        private static ContentManager content;

        /// <summary>
        /// 
        /// </summary>
        public static ContentManager Content
        {
            get { return content; }
        }


        private static Level level = new Level();

        /// <summary>
        /// 
        /// </summary>
        public static Level Level
        {
            get { return level; }
            set { level = value; }
        }


        private static bool debugging = false;

        /// <summary>
        /// 
        /// </summary>
        public static bool Debugging
        {
            get { return debugging; }
            set { debugging = value; }
        }


        private static bool paused;

        /// <summary>
        /// Gets or sets a value indicating whether the game is paused.
        /// </summary>
        /// <value><c>true</c> if paused; otherwise, <c>false</c>.</value>
        public static bool Paused
        {
            get { return paused; }
            set { paused = value; }
        }


        private static ScriptManager scriptManager;

        /// <summary>
        /// Gets the script manager.
        /// </summary>
        /// <value>The script manager.</value>
        public static ScriptManager ScriptManager
        {
            get { return scriptManager; }
        }

        private static List<IUpdateable> engineManagedComponents = new List<IUpdateable>();

        /// <summary>
        /// 
        /// </summary>
        public static List<IUpdateable> EngineManagedComponents
        {
            get { return engineManagedComponents; }
            set { engineManagedComponents = value; }
        }

        private static Game game;

        /// <summary>
        /// Gets and sets the Game associated with this GameComponent.
        /// </summary>
        /// <value></value>
        /// <returns>
        /// The Game associated with this GameComponent.
        /// </returns>
        public static new Game Game
        {
            [DebuggerStepThrough]
            get { return game; }
            [DebuggerStepThrough]
            set { game = value; }
        }

        private static Camera camera;

        /// <summary>
        /// Gets or sets the camera.
        /// </summary>
        /// <value>The camera.</value>
        public static Camera Camera
        {
            [DebuggerStepThrough]
            get { return camera; }
            [DebuggerStepThrough]
            set { camera = value; }
        }

        /// <summary>
        /// Initialises the global manager.
        /// </summary>
        public override void Initialize()
        {
            IGraphicsDeviceService gds = (IGraphicsDeviceService)(game.Services.GetService(typeof(IGraphicsDeviceService)));
            GraphicsHelper.GraphicsDevice = gds.GraphicsDevice;
            GraphicsHelper.SpriteBatch = new SpriteBatch(GraphicsHelper.GraphicsDevice);
            GraphicsHelper.DefaultFont = content.Load<SpriteFont>(@"Content\Fonts\DefaultFont");
            base.Initialize();

            Enabled = false;
        }


        private static PlayerManager playerManager;

        /// <summary>
        /// Gets the player manager.
        /// </summary>
        /// <value>The player manager.</value>
        public static PlayerManager PlayerManager
        {
            [DebuggerStepThrough]
            get { return playerManager; }
        }

        private static AIManager aiManager;

        /// <summary>
        /// Gets the AI manager.
        /// </summary>
        /// <value>The AI manager.</value>
        public static AIManager AIManager
        {
            [DebuggerStepThrough]
            get { return aiManager; }
        }
        private static WeaponManager weaponManager;

        /// <summary>
        /// Gets the weapon manager.
        /// </summary>
        /// <value>The weapon manager.</value>
        public static WeaponManager WeaponManager
        {
            [DebuggerStepThrough]
            get { return weaponManager; }
        }
        private static GameState currentState;

        /// <summary>
        /// 
        /// </summary>
        public static GameState CurrentState
        {
            get { return currentState; }
            set { currentState = value; }
        }


        /// <summary>
        /// Loads the player character.
        /// </summary>
        public static void LoadPlayerCharacter()
        {
            //playerManager.Player.Model = content.Load<Model>(@"Content\Models\Player\PlayerModel");
        }
        private Random random = new Random();

        /// <summary>
        /// Gets the random number generator.
        /// </summary>
        /// <value>The random.</value>
        public Random Random
        {
            [DebuggerStepThrough]
            get { return random; }
        }

        /// <summary>
        /// Creates an NPC character.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="characterName">Name of the character.</param>
        public void CreateNpcCharacter(string model, string characterName)
        {
            Agent agent = new Agent(characterName, "Generic", Game);
            agent.Health = 100;
            string name = Path.GetFileName(model);
            if (name == "{Random}")
            {
                string[] filenames = Directory.GetFiles(Path.GetDirectoryName(model));
                model = filenames[random.Next(filenames.Length)];
            }

            agent.Model = content.Load<Model>(Path.GetDirectoryName(Path.GetFullPath(model)) + Path.DirectorySeparatorChar + Path.GetFileNameWithoutExtension(model));
            agent.Visible = true;
            agent.Enabled = true;
            aiManager.Agents.Add(agent);
        }


    }
}